package Core;

import java.util.ArrayList;
import java.util.Observable;

public abstract class Game extends Observable
{
    protected Board board;
    protected Player player1, player2, currentPlayer;
    protected int alignement;

    public Game(Player player1, Player player2, Board board)
    {
	this.player1 = player1;
	this.player2 = player2;
	this.board = board;
	this.setChanged();
	this.notifyObservers();
    }

    protected boolean gridIsFilled()
    {
	for (int i = 0; i < this.board.getLines(); i++)
	{
	    for (int j = 0; j < this.board.getColumns(); j++)
	    {
		if (this.board.getSymbol(new Position(i, j))
			.equals(Symbol.NONE))
		    return false;
	    }
	}
	return true;
    }

    public boolean alignmentFound(Player p)
    {

	int column = p.getStrategy().getLastPosition().getColumn();
	int line = p.getStrategy().getLastPosition().getLine();
	int nbAlign = 1;
	boolean stop = false;

	System.out.println(line+" , "+column);
	// alignement vertical :
	// En montant
	for (int i = line - 1; i >= 0 && !stop; i--)
	{
	    if (this.board.getSymbol(new Position(i, column)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	}
	stop = false;
	// En descendant
	for (int i = line + 1; i < this.board.getLines() && !stop; i++)
	{
	    if (this.board.getSymbol(new Position(i, column)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	}
	stop = false;

	// alignement horizontal :
	nbAlign = 1;
	// Vers la droite
	for (int i = column - 1; i >= 0 && !stop; i--)
	{
	    if (this.board.getSymbol(new Position(line, i)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }

	}
	stop = false;
	// Vers la gauche :
	for (int i = column + 1; i < this.board.getColumns() && !stop; i++)
	{
	    if (this.board.getSymbol(new Position(line, i)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	}

	stop = false;
	// Diagonal : /
	// En montant
	nbAlign = 1;
	int j = column + 1;
	for (int i = line - 1; i >= 0 && j < this.board.getColumns() && !stop; i--)
	{

	    if (this.board.getSymbol(new Position(i, j)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	    j++;
	}
	j = column - 1;
	stop = false;
	// En descendant
	for (int i = line + 1; i < this.board.getLines() && j >= 0 && !stop; i++)
	{
	    if (this.board.getSymbol(new Position(i, j)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	    j--;
	}

	stop = false;
	// Diagonal : \
	// En montant
	nbAlign = 1;
	j = column - 1;
	for (int i = line - 1; i >= 0 && j >= 0 && !stop; i--)
	{

	    if (this.board.getSymbol(new Position(i, j)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	    j--;
	}
	j = column + 1;
	stop = false;
	// Vers le bas :
	for (int i = line + 1; i < this.board.getLines()
		&& j < this.board.getColumns() && !stop; i++)
	{

	    if (this.board.getSymbol(new Position(i, j)) == p.getSymbole())
	    {
		nbAlign++;
	    } else
	    {
		stop = true;
	    }
	    if (nbAlign == alignement)
	    {
		return true;
	    }
	    j++;
	}
	System.out.println(nbAlign);
	return false;
    }

    public abstract int valueForSymbol(Symbol s);

    public abstract boolean gameIsFinished();

    public abstract boolean gameIsDraw();

    public abstract ArrayList<Position> validMoves(Board board);

    public void play()
    {
	currentPlayer = player1;
	while (!gameIsFinished())
	{
	    this.board.display();
	    if (currentPlayer == player1)
	    {
		currentPlayer = player2;
	    } else
	    {
		currentPlayer = player1;
	    }

	    ArrayList<Position> validMoves = this.validMoves(board);
	    Position position = currentPlayer.play(validMoves, board);
	    board.set(position, currentPlayer.getSymbole());

	    this.notifyObservers();
	}
    }

    public Board getBoard()
    {
	return board;
    }

    public void setBoard(Board board)
    {
	this.board = board;
    }

    public Player getPlayer1()
    {
	return player1;
    }

    public void setPlayer1(Player player1)
    {
	this.player1 = player1;
    }

    public Player getPlayer2()
    {
	return player2;
    }

    public void setPlayer2(Player player2)
    {
	this.player2 = player2;
    }

    public Player getCurrentPlayer()
    {
	return currentPlayer;
    }

    public void setCurrentPlayer(Player currentPlayer)
    {
	this.currentPlayer = currentPlayer;
    }

    public void changeCurrentPlayer()
    {
	if (currentPlayer == player1)
	{
	    currentPlayer = player2;
	} else
	{
	    currentPlayer = player1;
	}
	this.setChanged();
	this.notifyObservers();
    }
}
